package com.pengheng.netty.server;

import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.ByteUtil;
import cn.hutool.core.util.HexUtil;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import lombok.extern.slf4j.Slf4j;

import java.io.UnsupportedEncodingException;
import java.nio.ByteOrder;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.*;

@Slf4j
public class NettyServerHandler extends ChannelInboundHandlerAdapter {
    /**
     * 客户端连接会触发
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        log.info("Channel active......");
    }

    /**
     * 客户端发消息会触发
     */
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {

        ByteBuf buf = (ByteBuf) msg;
        int count = buf.readableBytes();
        int myTag = 0;
        for (int i = 0; i < count - 1; i++) {
            myTag += buf.getUnsignedByte(i);
        }
        //校验码
        myTag = myTag & 0xff;

        int checkTag = buf.getUnsignedByte(buf.readableBytes() - 1);

        if (checkTag != myTag) {
            buf.clear();
            log.error("校验位不正确");
            return;
        }
        //报文头
        CharSequence msgHead = buf.readCharSequence(2, StandardCharsets.UTF_8);
        //报文类型
        short msgType = buf.readUnsignedByte();

        List<Map<String, Object>> listMap = new ArrayList<>();

        int msgLength = 0;
        byte flag = 0;
        int deviceCode = 0;
        if (msgType == 48) { //排队信息上报
            LocalDateTime dateTime = getUTCDateTime(buf);
            //目标数量
            short targetNum = buf.readUnsignedByte();

            int contentLength = 2 + 2 + 4 + 4 + 1 + 2 + 1 + 1 + 1 + 1;
            int bufLength = buf.readableBytes();
            for (int i = 0; i < (bufLength - 1) / contentLength; i++) {
                Map<String, Object> carInfo = new HashMap<>();
                carInfo.put("targetXPosition ", buf.readUnsignedShortLE());
                carInfo.put("targetYPosition ", buf.readUnsignedShortLE());
                carInfo.put("targetLon ", buf.readUnsignedIntLE());
                carInfo.put("targetLat ", buf.readUnsignedIntLE());
                carInfo.put("speed ", buf.readUnsignedByte());
                carInfo.put("targetHeading ", buf.readUnsignedShortLE());
                carInfo.put("targetRoadNum ", buf.readUnsignedByte());
                carInfo.put("targetLength ", buf.readUnsignedByte());
                carInfo.put("targetId ", buf.readUnsignedByte());
                carInfo.put("targetType ", buf.readUnsignedByte());
                listMap.add(carInfo);
            }

        } else {//报文长度
            msgLength = buf.readUnsignedShortLE();
            //设备编号
            deviceCode = buf.readUnsignedShortLE();
            //读写标识
            flag = buf.readByte();
            if (msgType == 41) {
                //上报时间
                LocalDateTime dateTime = getDateTime(buf);
                //上报周期
                int cycle = buf.readUnsignedShortLE();
                //车道总数
                int carRoadCount = buf.readUnsignedShortLE();

                int contentLength = 2 + 2 + 2 + 1 + 1 + 2 + 2 + 2 + 1 + 2 + 2 + 1 + 1 + 1;
                int bufLength = buf.readableBytes();
                for (int i = 0; i < (bufLength - 1) / contentLength; i++) {
                    Map<String, Object> carInfo = new HashMap<>();
                    carInfo.put("车道总流量 ", buf.readUnsignedShortLE());
                    carInfo.put("1行车流量 ", buf.readUnsignedShortLE());
                    carInfo.put("2行车流量 ", buf.readUnsignedShortLE());
                    carInfo.put("3行车流量 ", buf.readUnsignedShortLE());
                    carInfo.put("4行车流量 ", buf.readUnsignedShortLE());
                    carInfo.put("车道时间占有率 ", buf.readUnsignedByte());
                    carInfo.put("车道平均速度 ", buf.readUnsignedByte());
                    carInfo.put("车道最大排队长度 ", buf.readUnsignedShortLE());
                    carInfo.put("车道平均车头时距 ", buf.readUnsignedShortLE());
                    carInfo.put("车道平均车身间距 ", buf.readUnsignedShortLE());
                    carInfo.put("车道空间占有率 ", buf.readUnsignedByte());
                    carInfo.put("车道平均停车次数 ", buf.readUnsignedShortLE());
                    carInfo.put("车道平均延误时间 ", buf.readUnsignedShortLE());
                    carInfo.put("车道左转流量比例 ", buf.readUnsignedByte());
                    carInfo.put("车道直转流量比例 ", buf.readUnsignedByte());
                    carInfo.put("车道右转流量比例 ", buf.readUnsignedByte());
                    listMap.add(carInfo);
                }
            } else if (msgType == 44) {
                int contentLength = 6 + 1 + 1 + 1 + 2;
                int bufLength = buf.readableBytes();
                for (int i = 0; i < (bufLength - 1) / contentLength; i++) {
                    Map<String, Object> carInfo = new HashMap<>();
                    carInfo.put("车辆经过时刻 ", getDateTime(buf));
                    carInfo.put("车辆所在车道 ", buf.readUnsignedByte());
                    carInfo.put("车辆类型 ", buf.readUnsignedByte());
                    carInfo.put("车头时距 ", buf.readUnsignedByte());
                    carInfo.put("车身间距", buf.readUnsignedByte());
                    carInfo.put("车辆速度", buf.readUnsignedShortLE());
                    carInfo.put("车辆长度", buf.readUnsignedShortLE());
                    carInfo.put("车辆行驶方向", buf.readUnsignedByte());
                    listMap.add(carInfo);
                }
            } else if (msgType == 45) {
                int contentLength = 1 + 1 + 1 + 2;
                int bufLength = buf.readableBytes();
                for (int i = 0; i < (bufLength - 1) / contentLength; i++) {
                    Map<String, Object> carInfo = new HashMap<>();
                    carInfo.put("检车线圈号 ", buf.readUnsignedByte());
                    carInfo.put("驶入离开标志 ", buf.readUnsignedByte());
                    carInfo.put("速度", buf.readUnsignedByte());
                    carInfo.put("持续时间", buf.readUnsignedShortLE());
                    listMap.add(carInfo);
                }
            } else if (msgType == 60) {
                int contentLength = 2 + 2 + 2 + 1 + 1 + 1;
                int bufLength = buf.readableBytes();
                for (int i = 0; i < (bufLength - 1) / contentLength; i++) {
                    Map<String, Object> carInfo = new HashMap<>();
                    carInfo.put("车道排队长度 ", buf.readUnsignedShortLE());
                    carInfo.put("车道排队近端位置 ", buf.readUnsignedShortLE());
                    carInfo.put("车道排队远端位置", buf.readUnsignedShortLE());
                    carInfo.put("车道排队车辆数目", buf.readUnsignedByte());
                    carInfo.put("车辆排队超限", buf.readUnsignedByte());
                    carInfo.put("车道状态", buf.readUnsignedByte());
                    listMap.add(carInfo);
                }
            } else if (msgType == 200) {
                int contentLength = 6 + 1 + 2 + 2 + 2 + 2 + 1 + 1;
                int bufLength = buf.readableBytes();
                Map<String, Object> carInfo = new HashMap<>();
                carInfo.put("时间时间", getDateTime(buf));
                carInfo.put("事件车道", buf.readUnsignedByte());
                carInfo.put("告警X位置1 ", buf.readUnsignedShortLE());
                carInfo.put("告警Y位置1", buf.readUnsignedShortLE());
                carInfo.put("告警X位置2", buf.readUnsignedShortLE());
                carInfo.put("告警Y位置2", buf.readUnsignedShortLE());
                carInfo.put("告警类型 ", buf.readUnsignedByte());
                carInfo.put("备用 ", buf.readUnsignedByte());
                listMap.add(carInfo);
            } else {
                throw new IllegalStateException("Unexpected value: " + msgType);
            }
        }

    }

    private LocalDateTime getDateTime(ByteBuf buf) {
        short year = (short) (buf.readUnsignedByte() + 2000);
        short month = buf.readUnsignedByte();
        short day = buf.readUnsignedByte();
        short hour = buf.readUnsignedByte();
        short minute = buf.readUnsignedByte();
        short second = buf.readUnsignedByte();
        return LocalDateTime.of(year, month, day, hour, minute, second);
    }

    private LocalDateTime getUTCDateTime(ByteBuf buf) {
        byte[] bytes = new byte[8];
        bytes[6] = 0;
        bytes[7] = 0;
        for (int j = 0; j < 6; j++) {
            bytes[j] = buf.readByte();
        }
        //发送时间
        return LocalDateTimeUtil.of(ByteUtil.bytesToLong(bytes, ByteOrder.LITTLE_ENDIAN), TimeZone.getDefault());
    }

    /**
     * 发生异常触发
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.close();
    }


    public static void main(String[] args) throws UnsupportedEncodingException {
//        Double longitude = Double.valueOf("113.455744");
//        byte[] byteslongitude = ByteUtil.doubleToBytes(longitude);
//        System.out.println(byteslongitude.length);
//        System.out.println(ByteUtil.bytesToDouble(byteslongitude));
//
//        Double latitude = Double.valueOf("23.173311");
//        byte[] byteslatitude = ByteUtil.doubleToBytes(latitude);
//        System.out.println(byteslatitude.length);
//        System.out.println(ByteUtil.bytesToDouble(byteslatitude));


//        byte[] longarr = new byte[]{(byte) 0x3E, (byte) 0xA9, (byte) 0x61, (byte) 0x8E, (byte) 0x52, (byte) 0xE6, (byte) 0x9A, (byte) 0x26};
//        System.out.println(ByteUtil.bytesToDouble(longarr, ByteOrder.BIG_ENDIAN));

        String hexStr = "00000703403662166d29cf06405c6757520129a1034036629b0e63c5f8405c6788e3ff436d034036624e56d01b61405c67a9effdff4a034036617bb07a86af405c67a125ffeee3034036611a2a22be46405c67688bfaca8c034036615c7b2b1989405c6739c9fb364203403662702581efaf405c67299dfe5835013dcccccd3dcccccd0001023e4ccccd3e4ccccd0002033e99999a3e99999a0003043ecccccd3ecccccd0004053f0000003f0000000005063f19999a3f19999a0006073f3333333f3333330007";
        System.out.println("数据内容" + hexStr);
        byte[] bytes = HexUtil.decodeHex(hexStr);
        ByteBuf wrap = Unpooled.buffer();
        wrap.setBytes(0, bytes);
        System.out.println("数据长度" + wrap.capacity());
        System.out.println("任务类型" + wrap.readUnsignedByte());
        int i1 = wrap.readUnsignedShort();
        System.out.println("任务点数" + i1);
        System.out.println();

        //循环任务
        for (int i = 0; i < i1; i++) {
            byte typeBinary = wrap.readByte();
            System.out.println("任务类型" + typeBinary);
            System.out.println("是否为采样点" + (typeBinary & 0x01));
            System.out.println("是否为监测点" + (typeBinary >> 1 & 0x01));
            System.out.println("是否为测绘点" + (typeBinary >> 2 & 0x01));

            System.out.println("纬度" + wrap.readDouble());
            System.out.println("经度" + wrap.readDouble());
            System.out.println();
        }

        for (int i = 0; i < i1; i++) {
            System.out.println("采样瓶号码" + wrap.readUnsignedByte());
            System.out.println("采样容量" + wrap.readUnsignedShort());
            System.out.println("采样深度" + wrap.readUnsignedShort());
            System.out.println();
        }

        //循环采样瓶
        for (int i = 0; i < i1; i++) {
            System.out.println("监测数据测试时间长度" + wrap.readUnsignedShort());
            System.out.println();
        }
        //循环监测数据

    }
}